#include <chrono>
#include <vector>

#include "Network/ServerRoot.h"
#include "Network/Client.h"
#include "Network/PackageManager.h"
#include "Network/ConnectionManager.h"
#include "Network/BanManager.h"
#include "Network/ModsManager.h"
#include "Network/MessageManager.h"

#include "Network/FastPackages/ConnectionRequestPackage.h"
#include "Network/Packages/MessagePackage.h"
#include "Network/Packages/ClientPackage.h"

#include "Expand/PluginsManager.h"
#include "Expand/EventManager.h"

#include "ServerConfigure.h"
#include "Log.h"
#include "GameThreadPool.hpp"
#include "GameSingleton.h"
#include "GameRandom.hpp"
#include "GameRegistry.hpp"

#include "Managers/GameManager.h"

#include "LiteNetLib/NetManager.h"
#include "LiteNetLib/NetUtils.h"
#include "LiteNetLib/NetConnectRequestPacket.h"
#include "LiteNetLib/NetDebug.h"

using namespace LiteNetLib;

namespace PocketSurvival
{
    using namespace Engine;

    ServerRoot::ServerRoot() : m_saveTime(0.0f)
    {
        Log::Init();
        
        // NetDebug::Init();
        // NetDebug::logLevel = NetDebug::NetDebugLevel::LOG_INFO;

        GameSingleton::serverConfigure = GameSingleton::singletonPtr->registerSingleton<ServerConfigure>();
        GameSingleton::gameThreadPool = GameSingleton::singletonPtr->registerSingleton<GameThreadPool>();
        GameSingleton::gameNoWaitThreadPool = GameSingleton::singletonPtr->registerSingleton<GameNoWaitThreadPool>();
        GameSingleton::gameSaveThreadPool = GameSingleton::singletonPtr->registerSingleton<GameSaveThreadPool>();
        GameSingleton::gameRandom = GameSingleton::singletonPtr->registerSingleton<GameRandom>();
        GameSingleton::gameRegistry = GameSingleton::singletonPtr->registerSingleton<GameRegistry>();


        // 非 Managers 文件夹里面的 xxManager 类都要在这里加载（除了GameManager）
        GameSingleton::modsManager = GameSingleton::singletonPtr->registerSingleton<ModsManager>();
        GameSingleton::messageManager = GameSingleton::singletonPtr->registerSingleton<MessageManager>();
        GameSingleton::banManager = GameSingleton::singletonPtr->registerSingleton<BanManager>();
        GameSingleton::packageManager = GameSingleton::singletonPtr->registerSingleton<PackageManager>();
        GameSingleton::connectionManager = GameSingleton::singletonPtr->registerSingleton<ConnectionManager>();

        // Expand
        GameSingleton::eventManager = GameSingleton::singletonPtr->registerSingleton<EventManager>();
        GameSingleton::pluginsManager = GameSingleton::singletonPtr->registerSingleton<PluginsManager>();

        // 游戏部分内容
        GameSingleton::gameManager = GameSingleton::singletonPtr->registerSingleton<GameManager>();
        
        if (GameSingleton::serverConfigure->use0304)
        {
            // 这里没有0，因为0是服务器本身 （24.03.04包括之前的）
            for(int32_t index = 1; index < 256; index++)
            {
                m_clientIdSet.insert((uint8_t)index);
            }
        }
        else
        {
            for(int32_t index = 0; index < 256; index++)
            {
                m_clientIdSet.insert((uint8_t)index);
            }
        }
    }
    
    ServerRoot::~ServerRoot()
    {
        NetDebug::Dispose();
        Log::Dispose();
    }

    void ServerRoot::OnPeerConnected(NetPeerPtr &peer) {}

    // 收到客户端断开
    void ServerRoot::OnPeerDisconnected(NetPeerPtr &peer, DisconnectReason reason, const char* packet, uint32_t packetLength)
    {
        removeClientByAddressHashCode(peer->getHashCode());
    }

    // 收到客户端消息
    void ServerRoot::OnNetworkReceive(NetPeerPtr &peer, const char* packet, uint32_t packetLength, DeliveryMethod deliveryMethod)
    {
        // Log::Info(fmt::format("收到 {} 的 deliveryMethod 数据吧", peer->getAddress()));
        ClientPtr client = findClientByAddrHash(peer->getHashCode());
        if (client != nullptr)
        {
            // GameSingleton::packageManager->processPackage(client, packet, packetLength);
            GameSingleton::packageManager->addClientQueuePackage(client, packet, packetLength);
        }
        else
        {
            Log::Error("发生严重错误");
        }
    }

    // 收到非客户端的消息
    void ServerRoot::OnNetworkReceiveUnconnected(net_endpoint *endpoint, const char* packet, uint32_t packetLength, UnconnectedMessageType messageType)
    {
        GameSingleton::packageManager->processFastPackage(endpoint, packet, packetLength);
    }
    
    // 收到连接请求，一次pollEvent可能附带多次相同的连接请求，这里要记得检测
    void ServerRoot::OnConnectionRequest(ConnectionRequest *request)
    {
        size_t hashCode = NetUtils::SockHashCode(&(request->endpoint));

        m_clientsMapMutex.lock();
        bool isInServer = (m_clientsMap.find(hashCode) != m_clientsMap.end());
        m_clientsMapMutex.unlock();

        // 判断客户端是否已经连上服务器
        if (isInServer == false)
        {
            std::string addressStr = NetUtils::GetAddressStr(&(request->endpoint));
            Log::Info(fmt::format("接收到连接请求 : {}", addressStr));

            std::shared_ptr<ConnectionRequestPackage> package = std::make_shared<ConnectionRequestPackage>(&(request->endpoint));
            package->request = request;
            package->connectId = request->connectionTime;
            package->connectNum = request->connectionNumber;
            GameSingleton::packageManager->processFastPackage(&(request->endpoint), request->netDataReader.getUserData(), request->netDataReader.getUserDataSize(), package);
        }
        else
        {
            // 已经连接上的，直接同意并跳过即可
            request->accept();
        }
    }


    void ServerRoot::save()
    {
        Log::Info("Server saving...");        
        GameSingleton::gameManager->saveGame();
        GameSingleton::pluginsManager->save();

        GameSingleton::banManager->save();
        GameSingleton::connectionManager->save();
        GameSingleton::messageManager->save();
        GameSingleton::modsManager->save();
        GameSingleton::packageManager->save();

        GameSingleton::gameSaveThreadPool->wait_for_tasks();
        Log::Info("Server save ok");
    }


    // 服务器运行
    void ServerRoot::serverRun()
    {
        GameSingleton::banManager->load();
        GameSingleton::connectionManager->load();
        GameSingleton::messageManager->load();
        GameSingleton::modsManager->load();
        GameSingleton::packageManager->load();

        GameSingleton::pluginsManager->loadCorePluginsFiles();   // 加载原生插件，windows判断.dll文件，linux判断.so文件，这里只是加载文件，没有进行load
        GameSingleton::gameManager->loadGame();
        GameSingleton::pluginsManager->load();                   // 插件的加载必须放在 GameManager 之后，保证游戏内容已经加载，才能真正加载插件

        m_netManager = new NetManager(this);
        // m_netManager->unsyncedReceiveEvent = true;              // 异步收取数据包

        m_IsRun = m_netManager->start(GameSingleton::serverConfigure->host.c_str(), GameSingleton::serverConfigure->port);
        if (m_IsRun)
        {
            // Log::Info(fmt::format("Service started successfully, bind port: {}, host: {}", GameSingleton::serverConfigure->port, GameSingleton::serverConfigure->host));
            Log::Info(fmt::format("Service started successfully, bind address : {}",  m_netManager->getBindAddress()));


            auto LastTime = std::chrono::steady_clock::now();
            // 服务器刷新率，由配置文件中得tick决定
            static const auto msPerTick = std::chrono::milliseconds(1000 / GameSingleton::serverConfigure->tick);
            
            // 循环执行（帧处理），直到 m_IsRun 的值为 false
            while (m_IsRun)
            {
                // 先记录下现在的时间
                auto NowTime = std::chrono::steady_clock::now();
                // 跟下一次的时间做对比，好知道直接的间隔时间是多少
                auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count();

                m_netManager->pollUpdate(msec);
                // 帧刷新调用
                tick(static_cast<float>(msec) / 1000.0f);

                // 计算时间差，并进行休眠
                auto TickTime = std::chrono::steady_clock::now() - NowTime;
                // 
                if (TickTime < msPerTick)
                {
                    std::this_thread::sleep_for(msPerTick - TickTime);
                }
                // 记录时间
                LastTime = NowTime;
            }

            // 关闭所有客户端，加锁保证多线程安全性，不过这里其实也可以不用加锁了，因为已经跳出了帧刷新
            m_clientsMapMutex.lock();
            for(auto it = m_clientsMap.begin(); it != m_clientsMap.end(); ++it)
            {
                it->second->disconnect("服务器关闭");
            }
            m_clientsMapMutex.unlock();

            GameSingleton::gameNoWaitThreadPool->wait_for_tasks();
            // 保存数据
            save();
        }
        else
        {
            Log::Info("Service startup failed");
        }

        // 直接 delete 掉即可，LiteNetLib会自行关闭 udp 服务
        delete m_netManager;
        Log::Info("Server Stop");
    }

    /**
     * @brief 帧刷新处理
     * @param dt 距离上次刷新的间隔时间，单位:秒
    */
    void ServerRoot::tick(float dt)
    {
        // 导出 LiteNetLib 的事件，并进行处理
        m_netManager->pollEvents();
        GameSingleton::connectionManager->update(dt);

        // 用于检测玩家状态是否正常，防止有些玩家恶意卡连接
        for(auto it = m_clientsMap.begin(); it != m_clientsMap.end(); ++it)
        {
            GameSingleton::gameThreadPool->push_task(&Client::update, it->second.get(), dt);
            // it->second->update(dt);
        }

        // 处理控制台输入的信息
        std::string terminalMessage;
        while(m_terminalQueue.try_dequeue(terminalMessage))
        {
            if(terminalMessage.length() > 0)
            {
                // 首字母是 '/' 的就以命令的方式处理
                if(terminalMessage[0] == '/')
                {
                    if(GameSingleton::pluginsManager->processCmdMessage(nullptr, terminalMessage, true) != CmdRunType::Success)
                    {
                        Log::Info("命令不存在");
                    }
                }
                else // 其余的直接广播给所有的玩家
                {
                    Log::Info(fmt::format("[系统]: {}", terminalMessage));
                    GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<MessagePackage>(terminalMessage));
                }
            }
        }

        GameSingleton::gameThreadPool->wait_for_tasks();

        // 更新游戏部分
        GameSingleton::gameManager->update(dt);
        GameSingleton::gameThreadPool->wait_for_tasks();

        // 处理并发送数据包
        for(int32_t index = 0; index < GameSingleton::gameThreadPool->get_thread_count(); index++)
        {
            GameSingleton::gameThreadPool->push_task(std::bind(&PackageManager::sendQueuePackage, GameSingleton::packageManager));
        }

        m_saveTime += dt;
        // 5分钟保存一次
        if(m_saveTime >= serverRootSaveDataTime)
        {
            m_saveTime = 0;
            auto lastTime = std::chrono::steady_clock::now();
            save();
            auto nowTime = std::chrono::steady_clock::now();
            auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - lastTime).count();
            Log::Info(fmt::format("Server save use time : {}ms", msec));
        }

        GameSingleton::gameThreadPool->wait_for_tasks();
    }

    /**
     * @brief 创建游戏客户端对象，若对象创建成将会存到内部对象表中，没有创建则会返回 nullptr
     * @param peer LiteNetLib客户端对象
     * @param userGuid 玩家的GUID
     * @param nickname 玩家的游戏名称，没有写 "" 即可
    */
    ClientPtr ServerRoot::createClient(LiteNetLib::NetPeerPtr peer, const GameGuid &userGuid, const std::string &nickname)
    {
        if (peer == nullptr)
        {
            return nullptr;
        }
        std::lock_guard<SpinLock> lk(m_clientsMapMutex);
        // set表是有排序功能的，首位的数据肯定是最小的id值
        uint8_t clientId = *(m_clientIdSet.begin());
        m_clientIdSet.erase(m_clientIdSet.begin());

        ClientPtr client(new Client(peer, userGuid, clientId, nickname));

        m_clientIdMap[clientId] = client;
        m_clientsMap[peer->getHashCode()] = client;
        return client;
    }


    /**
     * @brief 通过地址 Hash 值来移除对应的游戏客户端
     * @param addressHashCode 地址 Hash 值
    */
    void ServerRoot::removeClientByAddressHashCode(size_t addressHashCode)
    {
        ClientPtr removeClient = nullptr;

        m_clientsMapMutex.lock();
        auto it = m_clientsMap.find(addressHashCode);
        if(it != m_clientsMap.end())
        {
            removeClient = it->second;
            m_clientIdMap[it->second->clientID] = nullptr;
            m_clientIdSet.insert(it->second->clientID);
            m_clientsMap.erase(it);
        }
        m_clientsMapMutex.unlock();

        if (removeClient != nullptr)
        {
            Log::Info(fmt::format("玩家 [{}]{} 断开了连接", removeClient->getAddress(), removeClient->nickname));
            removeClient->handleDisconnected();

            std::shared_ptr<ClientPackage> clientPackage = std::make_shared<ClientPackage>(removeClient, ClientPackageType::Remove);
            clientPackage->sendType = PackageSendType::ALL;
            GameSingleton::packageManager->addSendPackageToQueue(clientPackage);
        }
    }

    /**
     * @brief 通过 guid 查找对应的客户端
     * @return nullptr:没有查找到客户端
    */
    ClientPtr ServerRoot::findClientByGuid(const GameGuid& guid)
    {
        std::lock_guard<SpinLock> lk(m_clientsMapMutex);
        for(auto it = m_clientsMap.begin(); it != m_clientsMap.end(); ++it)
        {
            if(it->second->guid == guid)
            {
                return it->second;
            }
        }
        return nullptr;
    }

    /**
     * @brief 通过 地址hash值 查找对应的客户端
     * @return nullptr:没有查找到客户端
    */
    ClientPtr ServerRoot::findClientByAddrHash(size_t addressHashCode)
    {
        std::lock_guard<SpinLock> lk(m_clientsMapMutex);
        auto it = m_clientsMap.find(addressHashCode);
        if(it != m_clientsMap.end())
        {
            return it->second;
        }
        return nullptr;
    }


    /**
     * @brief 获取所有的客户端，包括没有加载 PlayerData 的客户端
     * @param outClients 客户端列表 
    */
    void ServerRoot::getAllClients(std::vector<ClientPtr> &outClients)
    {
        std::lock_guard<SpinLock> lk(m_clientsMapMutex);
        for(auto it = m_clientsMap.begin(); it != m_clientsMap.end(); ++it)
        {
            outClients.push_back(it->second);
        }
    }
}

